//
// Created by 28365 on 2025/3/6.
//

#ifndef ODUPDATERSDK_CURLCOMPATIBLE_H
#define ODUPDATERSDK_CURLCOMPATIBLE_H

#define byte curl_byte  // 重命名 byte
#include <curl/curl.h>
#undef byte  // 取消定义

#include <fstream>
#include <nlohmann/json.hpp>
#include "../include/config/server_api/ServerAPIState.h"
#include "ResponseType.h"
#include "../include/config/server_api/result_obj/ReqValue.h"
#include "../include/ODUpdater.h"
#include "../include/utils/JsonUtils.h"
#include "../include/exception/FileWriteExcpetion.h"
#include "obj/Res.h"

using namespace std;

class CURLCompatible {
private:
    //curl句柄
    CURL* curl = curl_easy_init();
    //响应码
    CURLcode code{};
    //返回体类型
    ResponseType responseType = JSON;
    //更新器实例
    const ODUpdater *odUpdater;
    //请求返回json
    string result{};
    //输出流，非下载时该值为nullptr
    ofstream *outStream = nullptr;
    //当前更新的资源
    const Res *res{};
    //当前资源的版本
    int version{};
    //文件大小
    size_t fileSize = -1;
    //已传输的数据量
    size_t transmitTotalSize = 0;

    //状态标识
    bool isSend = false;
    [[maybe_unused]] bool isHandle = false;

    //响应体处理回调函数
    static size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp);
    //响应头处理回调函数
    static size_t headerCallback(char* buffer, size_t size, size_t nitems, void* userdata);

public:

    explicit CURLCompatible(const ODUpdater *odUpdater);

    /**
     * 发送get请求
     * @param url 请求链接
     * @param param 请求参数
     */
    template<typename T>
    ReqValue<T> sendGet(const string& url,const map<string,string> &param);

    [[nodiscard]] void *getCurl() const;

    /**
     * 发送get请求
     * @param url 请求链接
     * @param param 请求参数
     * @param outStream 输出流
     */
    ReqValue<string> downloadFile(const string &url,const map<string,string> &param,ofstream *_outStream,const Res *_res,int _version){
        this->outStream = _outStream;
        this->res = _res;
        this->version = _version;
        return sendGet<string>(url,param);
    };

    void setResponseType(ResponseType responseType);

    void setResult(const string &result);

    [[nodiscard]] size_t getFileSize() const;

    void setFileSize(size_t fileSize);

    virtual ~CURLCompatible();

    [[nodiscard]] const ODUpdater &getOdUpdater() const;

    [[nodiscard]] const string &getResult() const;

    [[nodiscard]] ResponseType getResponseType() const;

    [[nodiscard]] ofstream *getOutStream() const;

    [[nodiscard]] size_t getTransmitTotalSize() const;

    void addTransmitSize(size_t size);
};

template<typename T>
ReqValue<T> CURLCompatible::sendGet(const string &url, const map<string, string> &param) {
    if (isSend){
        throw runtime_error("Each object can only send one request.");
    }
    isSend = true;
    fileSize = -1;
    responseType = JSON;
    isHandle = false;

    ReqValue<T> _result;

    if (curl){

        //完整的url，包含参数
        string completeUrl = url;
        if (!param.empty()){
            completeUrl.append("?");
            for (const auto &item: param){
                completeUrl.append(item.first).append("=").append(item.second).append("&");
            }
            completeUrl.erase(completeUrl.length() - 1, 1);
        }

        odUpdater->getLogger()->debug("尝试发送请求-->" + completeUrl);

        curl_easy_setopt(curl,CURLOPT_URL,completeUrl.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA,this);
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallback);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA,this);

        code = curl_easy_perform(curl);

        if (code == CURLE_OK){
            if (responseType == JSON){
                json j_r = json::parse(this->result);
                int r_code = j_r["code"];
                if (r_code == 30004){
                    _result.setServerApiState(MAXIMUM_DOWNLOAD);
                } else if (r_code != 200){
                    _result.setServerApiState(UNABLE_TO_CONNECT);
                } else{
                    JsonUtils::formJson<T>(j_r["data"],_result.getData());
                }

                _result.setMessage(j_r["message"]);
            } else if (responseType == FILE_DOWNLOAD && (outStream == nullptr || !outStream->is_open())){
                throw FileWriteException("文件无法写入");
            }
        } else{
            odUpdater->getLogger()->warn("请求异常->code:" + to_string(code));
            _result.setServerApiState(UNABLE_TO_CONNECT);
        }

    } else{
        odUpdater->getLogger()->warn("请求异常->curl句柄创建失败");
        _result.setServerApiState(UNABLE_TO_CONNECT);
    }

    isSend = false;

    return _result;
}


#endif //ODUPDATERSDK_CURLCOMPATIBLE_H
